package com.kun.order.service.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kun.api.ICouponService;
import com.kun.api.IGoodsService;
import com.kun.api.IOrderService;
import com.kun.api.IUserService;
import com.kun.common.constant.ShopCode;
import com.kun.common.exception.CustomerException;
import com.kun.order.service.mapper.TradeOrderMapper;
import com.kun.pojo.domain.*;
import com.kun.pojo.entity.MQEntity;
import com.kun.pojo.entity.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;

@Slf4j
@Service
@DubboService
public class OrderServiceImpl extends ServiceImpl<TradeOrderMapper, TradeOrder> implements IOrderService {

    @DubboReference
    private IGoodsService goodsService;

    @DubboReference
    private IUserService userService;

    @DubboReference
    private ICouponService couponService;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Value("${mq.order.topic}")
    private String topic;

    @Value("${mq.order.tag}")
    private String tag;

    /**
     * 确认订单
     */
    @Override
    public Result confirmOrder(TradeOrder order) {
        //1.校验订单
        checkOrder(order);
        //2.生成预订单
        savePreOrder(order);
        try {
            //3.扣减库存
            reduceGoodsNum(order);
            //4.扣减优惠券
            updateCouponStatus(order);
            //5.使用余额
            reduceMoneyPaid(order);
            //6.确认订单
            updateOrderStatus(order);
            //7.返回成功状态
            return Result.success(ShopCode.SHOP_SUCCESS.getMessage());
        } catch (Exception e) {
            //1.确认订单失败,发送消息
            MQEntity mqEntity = new MQEntity(order.getOrderId(), order.getUserId(), order.getMoneyPaid(),
                    order.getGoodsId(), order.getGoodsNumber(), order.getCouponId());
            //2.返回失败状态
            try {
                sendCancelOrder(topic, tag, mqEntity.getOrderId().toString(), JSON.toJSONString(mqEntity));
            } catch (MQBrokerException | RemotingException | InterruptedException | MQClientException ex) {
                ex.printStackTrace();
            }
            return new Result(ShopCode.SHOP_FAIL.getSuccess(), ShopCode.SHOP_FAIL.getMessage());
        }
    }

    /*
     * 发送失败信息进行回退
     * */
    private void sendCancelOrder(String topic, String tag, String keys, String body) throws MQBrokerException, RemotingException, InterruptedException, MQClientException {
        // 创建消息
        Message message = new Message(topic, tag, keys, body.getBytes());
        // 发送消息
        rocketMQTemplate.getProducer().send(message, 10000);
    }

    /**
     * 确认订单
     */
    private void updateOrderStatus(TradeOrder order) {
        boolean update = lambdaUpdate().set(TradeOrder::getOrderStatus, ShopCode.SHOP_ORDER_CONFIRM.getCode())
                .set(TradeOrder::getPayStatus, ShopCode.SHOP_ORDER_PAY_STATUS_NO_PAY.getCode())
                .set(TradeOrder::getConfirmTime, new Date())
                .eq(TradeOrder::getOrderId, order.getOrderId()).update();

        if (!update) throw new CustomerException(ShopCode.SHOP_ORDER_CONFIRM_FAIL);
        log.info("订单：{}确认订单成功", order.getOrderId());
    }

    /**
     * 扣减余额
     */
    private void reduceMoneyPaid(TradeOrder order) {
        if (order.getMoneyPaid() != null && order.getMoneyPaid().compareTo(BigDecimal.ZERO) > 0) {
            // 设置订单id，用户id和已支付钱数
            TradeUserMoneyLog tradeUserMoneyLog = new TradeUserMoneyLog();
            tradeUserMoneyLog.setOrderId(order.getOrderId());
            tradeUserMoneyLog.setUserId(order.getUserId());
            tradeUserMoneyLog.setUseMoney(order.getMoneyPaid());
            // 类型付款
            tradeUserMoneyLog.setMoneyLogType(ShopCode.SHOP_USER_MONEY_PAID.getCode());
            // 扣减余额，记录日志
            Result result = userService.reduceMoneyPaid(tradeUserMoneyLog);
            if (result.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess()))
                throw new CustomerException(ShopCode.SHOP_USER_MONEY_REDUCE_FAIL);
            log.info("订单：{}扣减余额成功！", order);
        }
    }

    /**
     * 使用优惠券
     */
    private void updateCouponStatus(TradeOrder order) {
        if (order.getCouponId() != null) {
            TradeCoupon tradeCoupon = couponService.findOne(order.getCouponId());
            tradeCoupon.setOrderId(order.getOrderId());
            tradeCoupon.setIsUsed(ShopCode.SHOP_COUPON_ISUSED.getCode());
            tradeCoupon.setUsedTime(new Date());
            // 更新优惠券状态
            Result result = couponService.updateCouponStatus(tradeCoupon);
            if (result.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess()))
                // 更新失败
                throw new CustomerException(ShopCode.SHOP_COUPON_USE_FAIL);
            log.info("订单：{}使用优惠券", order.getOrderId());
        }
    }

    /**
     * 扣减库存
     */
    private void reduceGoodsNum(TradeOrder tradeOrder) {
        Result result = goodsService.reduceGoodsNum(new TradeGoodsNumberLog(tradeOrder.getGoodsId(),
                tradeOrder.getOrderId(), tradeOrder.getGoodsNumber()));

        if (result.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess()))
            // 扣减失败
            throw new CustomerException(ShopCode.SHOP_REDUCE_GOODS_NUM_FAIL);
        log.info("订单：{}扣减库存成功！", tradeOrder.getOrderId());
    }

    /**
     * 生成预订单
     */
    private void savePreOrder(TradeOrder order) {
        // 1. 设置订单状态不可见
        order.setOrderStatus(ShopCode.SHOP_ORDER_NO_CONFIRM.getCode());
        // 2. 设置订单ID
        order.setOrderId(IdWorker.getId());
        // 3. 核算订单运费--这里简单些，如果余额大于100，免运费，否则10块运费
        BigDecimal shippingFee = calculateShippingFee(order);
        if (order.getShippingFee().compareTo(shippingFee) != 0)
            throw new CustomerException(ShopCode.SHOP_ORDER_SHIPPINGFEE_INVALID);
        // 4. 核算订单总金额是否合法
        BigDecimal orderAmount = order.getGoodsPrice().multiply(new BigDecimal(order.getGoodsNumber()));
        BigDecimal orderAmountAddShip = orderAmount.add(shippingFee);
        if (order.getOrderAmount().compareTo(orderAmountAddShip) != 0)
            throw new CustomerException(ShopCode.SHOP_ORDERAMOUNT_INVALID);
        // 5. 判断用户是否使用余额
        BigDecimal moneyPaid = order.getMoneyPaid();
        if (moneyPaid != null) {
            // 5.1 订单余额是否合法
            int r = moneyPaid.compareTo(BigDecimal.ZERO);
            // 余额小于0
            if (r < 0) throw new CustomerException(ShopCode.SHOP_MONEY_PAID_LESS_ZERO);
            // 余额大于0
            if (r > 0) {
                TradeUser user = userService.findOne(order.getUserId());
                if (moneyPaid.compareTo(BigDecimal.valueOf(user.getUserMoney())) > 0)
                    throw new CustomerException(ShopCode.SHOP_MONEY_PAID_INVALID);

            }
        } else {
            order.setMoneyPaid(BigDecimal.valueOf(0));
        }
        // 6. 判断用户是否使用优惠券
        Long couponId = order.getCouponId();
        if (couponId != null) {
            TradeCoupon tradeCoupon = couponService.findOne(couponId);
            // 判断优惠券是否为空
            if (tradeCoupon == null) throw new CustomerException(ShopCode.SHOP_COUPON_NO_EXIST);
            // 判断优惠券是否已经被使用
            if (tradeCoupon.getIsUsed().intValue() == ShopCode.SHOP_COUPON_ISUSED.getCode())
                throw new CustomerException(ShopCode.SHOP_COUPON_ISUSED);
            order.setCouponPaid(tradeCoupon.getCouponPrice());
        } else {
            // 如果没有传递优惠券，设置没有优惠券
            order.setCouponPaid(BigDecimal.ZERO);
        }
        // 7. 核算订单支付金额--订单总金额 - 余额 - 优惠券金额
        BigDecimal decimal = order.getOrderAmount().subtract(order.getMoneyPaid()).subtract(order.getCouponPaid());
        // 设置支付金额
        order.setPayAmount(decimal);
        // 设置下单时间
        order.setAddTime(new Date());
        // 保存数据库
        save(order);
    }

    /**
     * 核算运费
     */
    private static BigDecimal calculateShippingFee(TradeOrder order) {
        return order.getOrderAmount().compareTo(new BigDecimal(100)) > 0 ? BigDecimal.ZERO : new BigDecimal(10);
    }

    /**
     * 校验订单
     */
    private void checkOrder(TradeOrder order) {
        // 1. 校验订单是否存在
        if (order == null) throw new CustomerException(ShopCode.SHOP_ORDER_INVALID);
        // 2. 校验订单中的商品是否存在
        TradeGoods tradeGoods = goodsService.findOne(order.getGoodsId());
        if (tradeGoods == null) throw new CustomerException(ShopCode.SHOP_GOODS_NO_EXIST);
        // 3. 校验下单用户是否存在
        TradeUser tradeUser = userService.findOne(order.getUserId());
        if (tradeUser == null) throw new CustomerException(ShopCode.SHOP_USER_NO_EXIST);
        // 4. 校验商品单价是否合法
        int i = order.getGoodsPrice().compareTo(tradeGoods.getGoodsPrice());
        if (i != 0) throw new CustomerException(ShopCode.SHOP_GOODS_PRICE_INVALID);
        // 5. 校验订单商品数量是否合法---库存不足
        if (order.getGoodsNumber() >= tradeGoods.getGoodsNumber())
            throw new CustomerException(ShopCode.SHOP_GOODS_NUM_NOT_ENOUGH);
        log.info("校验订单通过");
    }
}
